package jp.androidgroup.chiba.androidresearch;

import java.util.ArrayList;
import java.util.List;

import jp.androidgroup.chiba.androidresearch.aws.Sdb;
import jp.androidgroup.chiba.androidresearch.data.Counter;
import jp.androidgroup.chiba.androidresearch.db.DatabaseHelper;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class SdbUpdateService extends IntentService {
	public static final String LOG_TAG = "SdbUpdateService";
	public static final int FIRST_INTERVAL = 10;
	public static final int INTERVAL = 5;
	private static final int MAX_LOOP = 20;

	private DatabaseHelper db_helper = null;
	private SQLiteDatabase wdb = null;

	public SdbUpdateService(String name) {
		super(name);
	}

	public SdbUpdateService() {
		super("SdbUpdateService");
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onHandleIntent(Intent intent) {
		int max_loop = MAX_LOOP;
		db_helper = new DatabaseHelper(this);
		wdb = db_helper.getWritableDatabase();
		while (max_loop > 0) {
			try {
				// 2 回目以降は sleep
				if (max_loop < MAX_LOOP) {
					Thread.sleep(INTERVAL * 1000);
				}
			} catch (InterruptedException e) {
				Log.d(LOG_TAG, "Interrupted sleep process");
				max_loop--;
				continue;
			}
			if (Common.isConnected(this)) {
				Log.d(LOG_TAG, "is online");
			} else {
				Log.d(LOG_TAG, "is offline");
				// 投稿できないので再度呼出
				max_loop--;
				continue;
			}
			
			wdb.beginTransaction();
			try {

				List<Counter> data_list = getLocalData();
				if (data_list.size() == 0) {
					// 投稿対象が存在しないので終了
					Log.d(LOG_TAG, "unupload data not found");
					break;
				}
				Log.d(LOG_TAG, "upload sdb start");
				if (insertSdb(this, data_list) == false) {
					// 投稿できないので再度呼出
					max_loop--;
					continue;
				}
				Log.d(LOG_TAG, "upload sdb end");
				Log.d(LOG_TAG, "updata local db start");
				saveLocalData(data_list);
				wdb.setTransactionSuccessful();
				Log.d(LOG_TAG, "updata local db end");
				Toast.makeText(this, "調査データをサーバへ登録しました。", Toast.LENGTH_LONG);
				break;
			} catch (SQLiteException e) {
				Log.d(LOG_TAG, e.toString());
				Log.d(LOG_TAG, "other process is updateing local database");
				max_loop--;
			} catch (Exception e) {
				Log.d(LOG_TAG, e.toString());
				Toast.makeText(this, "ERROR: 調査データのサーバへ登録に失敗しました。",
						Toast.LENGTH_LONG);
			} finally {
				wdb.endTransaction();
			}
			max_loop--;
		}
		// DB を close しないとエラーになった
		wdb.close();
	}

	@Override
	public void onDestroy()
	{
		Log.d(LOG_TAG, "finish service");
	}

	/**
	 * ローカルDB 更新
	 *
	 * UplaodDate を埋める
	 *
	 * @param data_list
	 * @throws Exception
	 */
	private void saveLocalData(List<Counter> data_list) throws Exception {
		try {
			for (int idx = 0; idx < data_list.size(); idx++) {
				data_list.get(idx).setUploadDate(Common.getNowDate());
				db_helper.save(wdb, data_list.get(idx));
			}
		} catch (Exception e) {
			throw e;
		}

	}

	/**
	 * SimpleDB へデータをアップロード
	 *
	 * @param context
	 * @param data_list
	 * @throws Exception
	 */
	private boolean insertSdb(Context context, List<Counter> data_list)
			throws Exception {
		try {
			for (int idx = 0; idx < data_list.size(); idx++) {
				Log.d(LOG_TAG, "upload data" + String.valueOf(idx));
				data_list.get(idx).setUploadDate(Common.getNowDate());
				Sdb.insertRequest(Sdb.getSdb(context), data_list.get(idx).getId(),
					data_list.get(idx));
			}
			return true;
		} catch (Exception e) {
			Log.d(LOG_TAG, e.toString());
			return false;
		}
	}

	/**
	 * 未登録のデータリストの取得
	 *
	 * @return List<Counter>
	 * @throws Exception
	 */
	private List<Counter> getLocalData() throws Exception {
		Counter counter = new Counter();
		try {
//			String[] columns = counter.getColumns();
			List<?> data = db_helper.find(wdb, Counter.class, null,
					"UploadDate is null", null);
			ArrayList<Counter> result = new ArrayList<Counter>();
			if (data.size() > 0) {
				for (int i = 0; i < data.size(); i++) {
					if (data.get(i).getClass().equals(counter.getClass())) {
						result.add((Counter) data.get(i));
					}
				}
			}
			else
			{
				Log.d(LOG_TAG, "local record not found.");
			}
			Log.d(LOG_TAG, "upload data coount=" + String.format("%d", result.size()));
			return result;
		} catch (Exception e) {
			Log.d(LOG_TAG, e.toString());
			throw e;
		}
	}
}